// Package main 实现了一个流式gRPC服务器，用于演示gRPC流式传输的使用
package main

import (
	"fmt"
	"grpc_study/stream_proto/proto"
	"io"
	"log"
	"net"
	"os"

	"google.golang.org/grpc"
)

// ServiceStream 定义流式服务结构体
type ServiceStream struct{}

// Fun 实现服务端流式RPC方法，向客户端发送多轮数据
// 参数:
//   - request: 客户端发送的请求参数
//   - stream: 服务端流接口，用于向客户端发送多个响应
//
// 返回值:
//   - error: 错误信息，nil表示无错误
func (ServiceStream) Fun(request *proto.Request, stream proto.ServiceStream_FunServer) error {
	// 打印客户端发送的请求信息
	fmt.Println(request)

	// 循环发送10轮数据给客户端
	for i := 0; i < 10; i++ {
		// 通过流接口发送响应数据
		stream.Send(&proto.Response{
			Text: fmt.Sprintf("第%d轮数据", i),
		})
	}

	// 返回nil表示处理成功
	return nil
}

// DownLoadFile 实现文件下载的流式RPC方法，向客户端发送文件内容
// 参数:
//   - request: 客户端发送的请求参数（包含文件相关信息）
//   - stream: 服务端流接口，用于向客户端发送文件数据块
//
// 返回值:
//   - error: 错误信息，nil表示无错误
func (ServiceStream) DownLoadFile(request *proto.Request, stream proto.ServiceStream_DownLoadFileServer) error {
	// 打印客户端发送的请求信息
	fmt.Println(request)

	// 打开要下载的文件
	file, err := os.Open("static/1.gvb_web项目搭建.mp4")
	if err != nil {
		// 如果文件打开失败，返回错误
		return err
	}

	// 确保在函数结束时关闭文件
	defer file.Close()

	// 循环读取文件内容并发送给客户端
	for {
		// 创建2048字节的缓冲区
		buf := make([]byte, 2048)

		// 从文件中读取数据到缓冲区
		_, err = file.Read(buf)

		// 如果读取到文件末尾，跳出循环
		if err == io.EOF {
			break
		}

		// 如果读取过程中出现其他错误，跳出循环
		if err != nil {
			break
		}

		// 通过流接口发送文件数据块给客户端
		stream.Send(&proto.FileResponse{
			Content: buf,
		})
	}

	// 返回nil表示处理成功
	return nil
}

// main 函数是程序的入口点，负责启动流式gRPC服务器
func main() {
	// 监听指定端口
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		// 如果监听失败，记录致命错误并退出程序
		log.Fatal(err)
	}

	// 创建gRPC服务器实例
	server := grpc.NewServer()

	// 注册流式服务
	proto.RegisterServiceStreamServer(server, &ServiceStream{})

	// 开始处理客户端请求
	server.Serve(listen)
}
